home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / filesyst / xiafs / xiafspgm.8 / xiafspgm / xiafspgm-0.8.1 / xfsck.c < prev   
C/C++ Source or Header  |  1993-03-22  |  30KB  |  1,134 lines

  1. /*
  2.  * xiafsck.c - xiafs file system checker
  3.  */
  4. /**************************************************************************
  5.  * (C) Copyright Q. Frank Xia, 1992.  All rights reserved.                *
  6.  *                                                                        *
  7.  * Permission to use and redistribute this software is hereby granted     *
  8.  * provided that the following conditions are met:                        *
  9.  * 1. Source code redistribution must retain this statement.              *
  10.  * 2. Binary redistribution must reproduce this statement in the          *
  11.  *    documentation provided with the distribution.                       *
  12.  * 3. This software is provided by author Q. Frank Xia "as is". There     *
  13.  *    are absolutely no warranties at all. The author is not responsible  *
  14.  *    for any possible damages caused by using this software.             *
  15.  **************************************************************************/
  16.  
  17. /*
  18.  * Usage: xiafsck [-{a|k|r|s}] device
  19.  *
  20.  *    -a    automatic repair.
  21.  *      -r    interactive repair.
  22.  *      -s    display super block info only.
  23.  *    -k    read the kernel image from the reserved space.
  24.  */
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <unistd.h>
  29. #include <signal.h>
  30. #include <fcntl.h>
  31. #include <termios.h>
  32. #include <sys/stat.h>
  33. #include <time.h>
  34. #include <sys/types.h>
  35. #include <linux/fs.h>
  36. #include <linux/xia_fs.h>
  37. #include <string.h>
  38. #include <ctype.h>
  39. #include <getopt.h>
  40.  
  41. #include "bootsect.h"
  42.  
  43. #if BLOCK_SIZE != 1024            /* BLOCK_SIZE must be 1024 */
  44. #error "only block size 1024 supported"
  45. #endif
  46.  
  47. #define ZONE_SIZE        (BLOCK_SIZE << zone_shift)
  48. #define BITS_PER_ZONE       (BLOCK_SIZE << (3 + zone_shift))
  49. #define BITS_PER_ZONE_BITS    (BLOCK_SIZE_BITS + 3 + zone_shift)
  50. #define ADDR_PER_ZONE       (BLOCK_SIZE >> (2 - zone_shift))
  51. #define INODES_PER_ZONE        (_XIAFS_INODES_PER_BLOCK << zone_shift)
  52.  
  53. #define NR_INODES    (INODE_ZONES * _XIAFS_INODES_PER_BLOCK << zone_shift)
  54. #define INODE_ZONES    (((zones - kern_zones) >> (2 + zone_shift)) \
  55.              / _XIAFS_INODES_PER_BLOCK + 1)
  56. #define IMAP_ZONES     (NR_INODES / BITS_PER_ZONE + 1)
  57. #define ZMAP_ZONES     ((zones - kern_zones) / BITS_PER_ZONE + 1)
  58. #define FIRST_KERN_ZONE (1 + IMAP_ZONES + ZMAP_ZONES + INODE_ZONES)
  59. #define FIRST_DATA_ZONE (FIRST_KERN_ZONE + kern_zones)
  60. #define NR_DATA_ZONES    (zones - FIRST_DATA_ZONE)
  61. #define MAX_SIZE    (zone_shift == 2 ? 0xffffffff : \
  62.              (((ADDR_PER_ZONE+1)*ADDR_PER_ZONE)+8)*ZONE_SIZE )
  63. #define INODE_MAX_ZONE  (8 + (1 + ADDR_PER_ZONE) * (ADDR_PER_ZONE))
  64. #define RNDUP(x)     (((x) + 3) & ~3) 
  65.  
  66. char   *pgm_name;        /* program name */
  67. int    rep=0;            /* cmd line switches */
  68. int    auto_rep=0;
  69. int    show_sup=0;
  70. int    read_kern=0;
  71. int    xiafs_dirt=0;
  72. int    zones;            /* size of file system in zones */
  73. int    kern_zones;        /* zones reserved for kernel image */
  74. int    first_data_zone;        /* as name said. */
  75. int    zone_shift=0;        /* ZONE_SIZE = BLOCK_SIZE << zone_shfit */
  76. int    dev;            /* device fd */
  77.  
  78. u_char *zmap_buf;        /* for zmap */
  79. u_char *zone_buf;        /* zone buffer */
  80. int    zone_addr=-1;        /* zone buffered */
  81. u_long *indz_buf;        /* for indirect zone */
  82. int    indz_addr=-1;        /* indirect zone buffered */
  83. u_long *dindz_buf;        /* for double indirect zone */
  84. int    dindz_addr=-1;        /* double indirect zone buffered */
  85.  
  86. #define imap_buf    zmap_buf    /* self document */
  87.  
  88. u_short *nlinks;        /* number of links counter */
  89.  
  90. /*-----------------------------------------------------------------------
  91.  * error process rutines
  92.  */
  93. void usage()
  94. {
  95.     fprintf(stderr, "usage: %s [-{a|k|r|s}] device\n", pgm_name);
  96.     exit(1);
  97. }
  98.  
  99. void die(char *cp)
  100. {
  101.     fprintf(stderr, "%s: %s\n", pgm_name, cp);
  102.     exit(1);
  103. }
  104.  
  105. /*------------------------------------------------------------------------
  106.  * error free read/write rutines
  107.  */
  108. void rd_zone(int zone_nr, void *buffer)
  109. {
  110.     if (lseek(dev, zone_nr * ZONE_SIZE, SEEK_SET) < 0)
  111.         die("seek device failed");
  112.     if (read(dev, buffer, ZONE_SIZE) < 0)
  113.         die("reading device failed");
  114. }
  115.  
  116. void wt_zone(int zone_nr, void *buffer)
  117. {
  118.     if (lseek(dev, zone_nr * ZONE_SIZE, SEEK_SET) < 0)
  119.         die("seek device failed.");
  120.     if (write(dev, buffer, ZONE_SIZE) < 0)
  121.         die("write device failed.");
  122. }
  123.  
  124. /*----------------------------------------------------------------------
  125.  * directory entries stack process rutines. automatic space locating.
  126.  */
  127. struct path_t {
  128.     u_long ino;
  129.     u_short rec_len;
  130.     u_short pre_rec_len;
  131.     char name[256];
  132. };
  133.  
  134. u_char *path=(u_char *)0;              /* stack for making a path */
  135. u_char *path_end=(u_char *)0;        /* stack end */
  136.  
  137. struct path_t *path_top=(struct path_t *)0;     /* stack pointer */
  138.  
  139. void push_de(struct xiafs_direct * de)
  140. {
  141.     /* the caller chould do error check for de to avoid segm fault */
  142.  
  143.     int tmp, size, pos;
  144.  
  145.     if (!path) {                /* first time */
  146.         if ( !(path = (u_char *)malloc(BLOCK_SIZE + 4)) )
  147.         die("allocate memory failed");
  148.     path_end = path + BLOCK_SIZE;
  149.     }
  150.     if ( !path_top ) {                /* stack empty */ 
  151.     path_top= (struct path_t *)path;
  152.     path_top->pre_rec_len = 0;
  153.     } else {
  154.         tmp=path_top->rec_len;
  155.     path_top=(struct path_t *)((u_char *)path_top+tmp);
  156.     path_top->pre_rec_len=tmp;
  157.     }
  158.     tmp = RNDUP(de->d_name_len + 1) + 8;
  159.     if (((u_char *)path_top + tmp) >= path_end) {
  160.         size = path_end - path + BLOCK_SIZE;
  161.     pos = (u_char *)path_top - path;
  162.     if ( !(path = (u_char *) realloc(path, size + 4)) )
  163.         die("allocate memory failed.");
  164.     path_end = path + size;
  165.     path_top = (struct path_t *)(path + pos);
  166.     }
  167.     path_top->rec_len=tmp;
  168.     path_top->ino = de->d_ino;
  169.     strncpy(path_top->name, de->d_name, de->d_name_len+1);
  170. }
  171.  
  172. void pop_de()
  173. {
  174.     int tmp;
  175.  
  176.     if ((u_char *)path_top == path) 
  177.         path_top=NULL;
  178.     else {
  179.         tmp=path_top->pre_rec_len;
  180.     path_top=(struct path_t *)((u_char *)path_top-tmp);
  181.     }
  182. }
  183.  
  184. ino_t pre_ino()
  185. {
  186.     struct path_t *pp;
  187.  
  188.     pp=(struct path_t *)((u_char *)path_top-path_top->pre_rec_len);
  189.     return pp->ino; 
  190. }
  191.  
  192. #define cur_ino()        (path_top->ino)
  193.  
  194. void print_path()
  195. {
  196.     struct path_t *pp;
  197.     int ino=0;
  198.      
  199.     if (!path_top)
  200.         return;
  201.     if (path==(u_char *)path_top) {
  202.         if (path_top->ino==_XIAFS_ROOT_INO) {
  203.         printf("/   ino=%d (0x%x)\n", _XIAFS_ROOT_INO, _XIAFS_ROOT_INO);
  204.         return;
  205.     }
  206.     if (path_top->ino==_XIAFS_BAD_INO) {
  207.         printf("[bad_blocks]   ino=%d (0x%x)\n", _XIAFS_BAD_INO, _XIAFS_BAD_INO);
  208.         return;
  209.     }
  210.     } 
  211.     pp=(struct path_t *)path;
  212.     pp=(struct path_t *)((u_char *)pp+pp->rec_len);
  213.     while (pp <= path_top) {
  214.         ino=pp->ino;
  215.         printf("/%s", pp->name);
  216.     pp=(struct path_t *)((u_char *)pp+pp->rec_len);
  217.     }
  218.     printf("   ino=%d (0x%x)\n", ino, ino);
  219. }
  220.  
  221. /*----------------------------------------------------------------------
  222.  * interactive rutine
  223.  */
  224. int ask_rep(char *msg)
  225. {
  226.     char c;
  227.  
  228.     print_path();
  229.     if (!rep && !auto_rep) {
  230.         printf("---- %s\n\n", msg);
  231.     return 0;
  232.     }
  233.     if (auto_rep) {
  234.         printf("---- %s\n\n", msg);
  235.     xiafs_dirt=1;
  236.     return 1;
  237.     }
  238.     fflush(stdin);
  239.     printf("---- %s Repair ?: [y/n/a] ", msg);
  240.     fflush(stdout);
  241.     c=getchar();
  242.     printf("\n\n");
  243.     if ((c=toupper(c))=='Y') {
  244.         xiafs_dirt=1;
  245.         return 1;
  246.     }
  247.     else if (c=='A') {
  248.         xiafs_dirt=1;
  249.         auto_rep=1;
  250.     rep=0;
  251.     return 1;
  252.     } 
  253.     return 0;
  254. }
  255.     
  256. /*----------------------------------------------------------------------
  257.  *  check super block
  258.  */
  259. void ck_sup_zone()
  260. {
  261.     struct xiafs_super_block * sp;
  262.  
  263.     rd_zone(0, zone_buf);
  264.     sp=(struct xiafs_super_block *)zone_buf;
  265.  
  266.     /* primary data */
  267.     if (sp->s_magic != _XIAFS_SUPER_MAGIC)
  268.         die("magic number mismatch");
  269.     zones=sp->s_nzones;
  270.     zone_shift=sp->s_zone_shift;
  271.     if (zone_shift && zone_shift != 1 && zone_shift != 2)
  272.         die("zone size != 1, 2, or 4 KB");
  273.     if ((zones << zone_shift) > 0x400000 || zones < 0) 
  274.         die("invalid nzones");
  275.     first_data_zone=sp->s_firstdatazone;
  276.     if (!sp->s_firstkernzone)
  277.         kern_zones=0;
  278.     else
  279.         kern_zones=first_data_zone-sp->s_firstkernzone;
  280.  
  281.     /* derived data */
  282.     if (sp->s_zone_size != BLOCK_SIZE << zone_shift ||
  283.         sp->s_ninodes != NR_INODES ||
  284.         sp->s_imap_zones != IMAP_ZONES ||
  285.         sp->s_zmap_zones != ZMAP_ZONES ||
  286.         (sp->s_firstkernzone && sp->s_firstkernzone < FIRST_KERN_ZONE) ||
  287.         kern_zones < 0 ||
  288.         first_data_zone > zones ||
  289.         sp->s_ndatazones != NR_DATA_ZONES ||
  290.         sp->s_max_size != MAX_SIZE )
  291.         die("super block data inconsistent");
  292. }
  293.  
  294.  
  295. void show_sup_zone()
  296. {
  297.   struct xiafs_super_block *sp;
  298.   int tmp;
  299.   
  300.   sp=(struct xiafs_super_block *)zone_buf;
  301.   printf(  "        zone size: %u (0x%X) bytes\n", sp->s_zone_size, 
  302.                                 sp->s_zone_size);
  303.   printf(  "  number of zones: %u (0x%X)\n", sp->s_nzones, 
  304.                          sp->s_nzones);
  305.   printf(  " number of inodes: %u (0x%X)\n", sp->s_ninodes, 
  306.                          sp->s_ninodes);
  307.   printf(  "       imap zones: %u (0x%X)\n", sp->s_imap_zones, 
  308.                          sp->s_imap_zones);
  309.   printf(  "       zmap zones: %u (0x%X)\n", sp->s_zmap_zones, 
  310.                          sp->s_zmap_zones);
  311.   if (sp->s_firstkernzone)
  312.     printf("first kernal zone: %u (0x%X)\n", sp->s_firstkernzone, 
  313.                          sp->s_firstkernzone);
  314.   printf(  "  first data zone: %u (0x%X)\n", sp->s_firstdatazone, 
  315.                          sp->s_firstdatazone);
  316.   printf(  "       zone shift: %u\n", sp->s_zone_shift);
  317.   tmp=sp->s_max_size >> 20;
  318.   if (zone_shift==2)
  319.     tmp++;
  320.   printf(  "    max file size: %u (0x%X) MB\n", tmp, tmp);
  321.   printf(  "      xiafs magic: %u (0x%X) ---%s\n", sp->s_magic, 
  322.                             sp->s_magic, 
  323.           (sp->s_magic==_XIAFS_SUPER_MAGIC) ? "match" : "mismatch");
  324.   if (!sp->s_firstkernzone)
  325.     printf("no zones reserved for kernal image\n");
  326. }
  327.  
  328. /*-------------------------------------------------------------------------
  329.  * 
  330.  */
  331. void rd_inode(u_long ino, struct xiafs_inode *ip)
  332. {
  333.     int ino_addr, ino_off;
  334.  
  335.     ino_addr= 1 + IMAP_ZONES + ZMAP_ZONES + ((ino-1) / INODES_PER_ZONE);
  336.     ino_off=(ino-1) & (INODES_PER_ZONE - 1);
  337.     if (zone_addr != ino_addr) {
  338.         zone_addr=ino_addr;
  339.     rd_zone(ino_addr, zone_buf);
  340.     }
  341.     memcpy(ip, ino_off+(struct xiafs_inode *)zone_buf, sizeof(struct xiafs_inode));
  342. }
  343.  
  344. void wt_inode(u_long ino, struct xiafs_inode *ip)
  345. {
  346.     int ino_addr, ino_off;
  347.  
  348.     ino_addr = 1 + IMAP_ZONES + ZMAP_ZONES + (ino-1) / INODES_PER_ZONE;
  349.     ino_off = (ino-1) & (INODES_PER_ZONE -1);
  350.     if (zone_addr != ino_addr) {
  351.         zone_addr=ino_addr;
  352.     rd_zone(ino_addr, zone_buf);
  353.     }
  354.     memcpy((struct xiafs_inode *)zone_buf+ino_off, ip, sizeof(struct xiafs_inode));
  355.     wt_zone(ino_addr, zone_buf);
  356. }
  357.  
  358. /*------------------------------------------------------------------------
  359.  *  display the block numbers which are marked as bad zones
  360.  */
  361.  
  362. void show_badnum(u_long num)
  363. {
  364.     static count=0;
  365.  
  366.     num &= 0xffffff;
  367.     if (!count)
  368.         printf("bad block number list:");
  369.     if (!(count & 7))
  370.         printf("\n");
  371.     if (zone_shift) {
  372.         count += 2;
  373.     printf("%8u--%8u  ", num << zone_shift, ((num + 1) << zone_shift)-1);
  374.     } else {
  375.         count++;
  376.     printf("%8u  ", num);
  377.     }
  378. }
  379.  
  380. void show_badblks()
  381. {
  382.     struct xiafs_inode bi;
  383.     int i, j, k, bz, tmp;
  384.  
  385.     rd_inode(2, &bi);
  386.     if (bi.i_size & (ZONE_SIZE-1))
  387.         fprintf(stderr, "bad size in inode 2\n");
  388.     bz=(bi.i_size + ZONE_SIZE -1) / ZONE_SIZE;
  389.     tmp= bz > 8 ? 8 : bz;
  390.     for (i=0; i < tmp; i++)
  391.         show_badnum(bi.i_zone[i]);
  392.     bz -= 8;
  393.     if (bz <= 0)
  394.     goto showed;
  395.     if (indz_addr != bi.i_ind_zone) {
  396.         indz_addr = bi.i_ind_zone;
  397.     rd_zone(indz_addr, indz_buf);
  398.     }
  399.     tmp= bz > ADDR_PER_ZONE ? ADDR_PER_ZONE : bz;
  400.     for (i=0; i < tmp; i++)
  401.         show_badnum(indz_buf[i]);
  402.     bz -= ADDR_PER_ZONE;
  403.     if (bz <= 0)
  404.         goto showed;
  405.     tmp= (bz + ADDR_PER_ZONE -1) / ADDR_PER_ZONE;
  406.     bz &= ADDR_PER_ZONE-1;
  407.     k=ADDR_PER_ZONE;
  408.     if (dindz_addr != bi.i_dind_zone) {
  409.         dindz_addr=bi.i_dind_zone;
  410.     rd_zone(dindz_addr, dindz_buf);
  411.     }
  412.     for (j=0; j < tmp; j++) {
  413.         if (indz_addr != bi.i_ind_zone) {
  414.         indz_addr=bi.i_dind_zone;
  415.         rd_zone(indz_addr, indz_buf);
  416.     }
  417.         if (j == tmp -1)
  418.         k = bz;
  419.         for (i=0; i < k; i++)
  420.         show_badnum(indz_buf[i]);
  421.     }
  422. showed:
  423.     printf("\n");
  424. }
  425.       
  426. /*------------------------------------------------------------------------
  427.  * directory misc rutines.
  428.  */
  429.  
  430. u_long get_addr(struct xiafs_inode *ip, int indx)
  431. {
  432.   u_long addr;
  433.  
  434.   if (indx < 0 || indx >= INODE_MAX_ZONE)
  435.       return 0;
  436.   if (indx < 8)
  437.       return (ip->i_zone[indx] & 0xffffff);
  438.  
  439.   indx -=8;
  440.   if (indx < ADDR_PER_ZONE) {
  441.       if ( indz_addr != (ip->i_ind_zone & 0xffffff) ) {
  442.       indz_addr=ip->i_ind_zone & 0xffffff;
  443.       if (indz_addr < first_data_zone || indz_addr >= zones)
  444.           return 0;
  445.       rd_zone(ip->i_ind_zone, indz_buf);
  446.       }
  447.       return indz_buf[indx];
  448.   }
  449.   indx -= ADDR_PER_ZONE;
  450.   if ( dindz_addr != (ip->i_dind_zone & 0xffffff) ) {
  451.       dindz_addr=ip->i_dind_zone & 0xffffff;
  452.       if (dindz_addr < first_data_zone || dindz_addr >= zones)
  453.       return 0;
  454.       rd_zone(ip->i_dind_zone, dindz_buf);
  455.   }
  456.   addr=dindz_buf[indx / ADDR_PER_ZONE];
  457.   if ( indz_addr != addr ) {
  458.       indz_addr=addr;
  459.       if (addr < first_data_zone || addr >= zones)
  460.       return 0;
  461.       rd_zone(addr, indz_buf);
  462.   }
  463.   return indz_buf[indx & (ADDR_PER_ZONE-1)];
  464. }
  465.  
  466. struct da_t {
  467.     struct xiafs_inode inode;
  468.     u_long zone;
  469.     u_long addr;
  470.     struct xiafs_direct *pre_de;
  471.     struct xiafs_direct *cur_de;
  472. };
  473.  
  474. static struct da_t *da=(struct da_t *)0;
  475. static int da_size=0;
  476. static int da_top=-1;
  477.   
  478. int start_dir(struct xiafs_inode *ip)
  479. {
  480.     struct xiafs_direct *de;
  481.  
  482.     if (ip->i_size & (ZONE_SIZE -1))
  483.         return -1;
  484.     if ((++da_top)*sizeof(struct da_t) >= da_size) {
  485.         da_size += 16*sizeof(struct da_t);
  486.     if (!(da=(struct da_t *)realloc(da, da_size)))
  487.         die("allocate memory failed.");
  488.     }
  489.     da[da_top].inode=*ip;
  490.     da[da_top].zone=0;
  491.     da[da_top].addr=ip->i_zone[0];
  492.     if (zone_addr!=ip->i_zone[0]) {
  493.         zone_addr=ip->i_zone[0];
  494.     rd_zone(zone_addr, zone_buf);
  495.     }
  496.     de=(struct xiafs_direct *)zone_buf;
  497.     if (de->d_ino <= 0 || de->d_ino > NR_INODES || de->d_rec_len!=12 ||
  498.         de->d_name_len!=1 || de->d_name[0] != '.' || de->d_name[1])
  499.         return -1;
  500.     nlinks[de->d_ino-1]++;
  501.     de=(struct xiafs_direct *)((u_char *)de + 12);
  502.     if (de->d_ino!=pre_ino() || de->d_name_len!=2 || de->d_rec_len < 12 || 
  503.         (u_char *)de + de->d_rec_len > zone_buf + ZONE_SIZE || 
  504.         strcmp(de->d_name, "..") )
  505.         return -1;
  506.     nlinks[de->d_ino-1]++;
  507.     da[da_top].pre_de=(struct xiafs_direct *)zone_buf;
  508.     da[da_top].cur_de=de;
  509.     return 0;
  510. }
  511.  
  512. int get_de(struct xiafs_direct * res_de)
  513. {
  514.     /* return -1 on error, 0 on EOF, else 1 */
  515.  
  516.     struct xiafs_direct *de;
  517.  
  518.     if (da[da_top].addr != zone_addr) {
  519.         zone_addr=da[da_top].addr;
  520.     rd_zone(zone_addr, zone_buf);
  521.     }
  522.     da[da_top].pre_de=da[da_top].cur_de;
  523.     de=(struct xiafs_direct *)
  524.         ((u_char *)(da[da_top].cur_de)+da[da_top].cur_de->d_rec_len);
  525.     if ( (u_char *)de >= zone_buf + ZONE_SIZE ) {
  526.         while (da[da_top].inode.i_size > ++(da[da_top].zone) * ZONE_SIZE) {
  527.         zone_addr=get_addr(&(da[da_top].inode), da[da_top].zone);
  528.         rd_zone(zone_addr, zone_buf);
  529.         de=(struct xiafs_direct *)zone_buf;
  530.         if (de->d_ino || de->d_rec_len < ZONE_SIZE)
  531.             break;
  532.     }
  533.     if (da[da_top].inode.i_size <= da[da_top].zone * ZONE_SIZE)
  534.         return 0;
  535.     da[da_top].pre_de=de;
  536.     if (!de->d_ino)
  537.         de=(struct xiafs_direct *)(zone_buf+de->d_rec_len);
  538.     da[da_top].addr=zone_addr;
  539.     }
  540.     da[da_top].cur_de=de;
  541.     if (de->d_rec_len < 12 || (u_char *)de+de->d_rec_len > zone_buf+ZONE_SIZE 
  542.         || de->d_name_len <= 0 || de->d_name_len + 8 > de->d_rec_len 
  543.         || de->d_ino < 1 || de->d_ino > NR_INODES 
  544.         || de->d_name[de->d_name_len])
  545.         return -1;
  546.     res_de->d_ino=de->d_ino;
  547.     res_de->d_rec_len=de->d_rec_len;
  548.     res_de->d_name_len=de->d_name_len;
  549.     strncpy(res_de->d_name, de->d_name, de->d_name_len+1);
  550.     return 1;
  551. }
  552.  
  553. void rep_de()
  554. {
  555.     struct xiafs_direct *de;
  556.  
  557.     if (zone_addr != da[da_top].addr) {
  558.         zone_addr = da[da_top].addr;
  559.     rd_zone(zone_addr, zone_buf);
  560.     }
  561.     de=da[da_top].cur_de;
  562.     if ((u_char *)de==zone_buf) {
  563.         de->d_rec_len=ZONE_SIZE;
  564.     de->d_ino=0;
  565.     de->d_name_len=0;
  566.     } else {
  567.         da[da_top].pre_de->d_rec_len += zone_buf+ZONE_SIZE - (u_char *)de;
  568.     da[da_top].cur_de=da[da_top].pre_de;
  569.     }
  570.     wt_zone(zone_addr, zone_buf);
  571. }
  572.  
  573. void del_de()
  574. {
  575.     if (zone_addr != da[da_top].addr) {
  576.         zone_addr=da[da_top].addr;
  577.     rd_zone(zone_addr, zone_buf);
  578.     }
  579.     if ((u_char *)da[da_top].cur_de==zone_buf) {
  580.         da[da_top].cur_de->d_ino=0;
  581.     da[da_top].cur_de->d_name_len=0;
  582.     } else {
  583.         da[da_top].pre_de->d_rec_len += da[da_top].cur_de->d_rec_len;
  584.     da[da_top].cur_de=da[da_top].pre_de;
  585.     }
  586.     wt_zone(zone_addr, zone_buf);
  587. }
  588.  
  589. #define end_dir()     (da_top--)
  590.  
  591. /*------------------------------------------------------------------------
  592.  *
  593.  */
  594. #define z_to_bnr(addr)        (((addr) & 0xffffff)-first_data_zone+1)
  595.  
  596. int test_set_zbit(int addr)
  597. {
  598.     int byte_nr, bit_off;
  599.  
  600.     addr &= 0xffffff;
  601.     if (!addr)            /* is a hole */
  602.         return 0;
  603.     bit_off = z_to_bnr(addr); 
  604.     byte_nr = bit_off >> 3;
  605.     bit_off &= 7;
  606.  
  607.     if (zmap_buf[byte_nr] & (1 << bit_off))
  608.       return -1;
  609.  
  610.     zmap_buf[byte_nr] |= (1 << bit_off);
  611.     return 0;
  612. }
  613.  
  614. void ck_zmap()
  615. {
  616.     int i, j, k, dirt;
  617.     char msg[80];
  618.  
  619.     zmap_buf[0] |= 1;
  620.     if ((i=(NR_DATA_ZONES+1) >> 3) < ZMAP_ZONES*ZONE_SIZE)
  621.         zmap_buf[i] |= 255 << ((NR_DATA_ZONES+1) & 7);
  622.     if (i+1 < ZMAP_ZONES*ZONE_SIZE)
  623.         memset(zmap_buf+i+1, 0xff, ZMAP_ZONES*ZONE_SIZE-i-1);
  624.     for (i=0; i < ZMAP_ZONES; i++) {
  625.         rd_zone(1+IMAP_ZONES+i, zone_buf);
  626.     dirt=0;
  627.     for (j=0; j < ZONE_SIZE; j++) {
  628.         if (zone_buf[j]^zmap_buf[i*ZONE_SIZE+j]) {
  629.             for (k=0; k < 8; k++) {
  630.             if ((zone_buf[j] & (1<<k)) && 
  631.                 !(zmap_buf[i*ZONE_SIZE+j] & (1<<k))) {
  632.                 sprintf(msg, "free zone %u (0x%X) marked as used.", 
  633.                 (i*ZONE_SIZE+j)*8+k, (i*ZONE_SIZE+j)*8+k);
  634.             if (ask_rep(msg)) {
  635.                 zone_buf[j] &= ~(1<<k);
  636.                 dirt=1;
  637.             }
  638.             }
  639.             if (!(zone_buf[j] & (1<<k)) && 
  640.                   (zmap_buf[i*ZONE_SIZE+j] & (1<<k))) {
  641.                 sprintf(msg, "used zone %u (0x%X) marked as free.",
  642.                 (i*ZONE_SIZE+j)*8+k, (i*ZONE_SIZE+j)*8+k);
  643.             if (ask_rep(msg)) {
  644.                 zone_buf[j] |= (1<<k);
  645.                 dirt=1;
  646.             }
  647.             }
  648.         }
  649.         }
  650.     }
  651.     if (dirt)
  652.         wt_zone(1+IMAP_ZONES+i, zone_buf);
  653.     }
  654. }
  655.  
  656. /*------------------------------------------------------------------------
  657.  *
  658.  */
  659. void ck_nlinks()
  660. {
  661.     int i, j, dirt;
  662.     struct xiafs_inode *i_pt;
  663.     char msg[80];
  664.  
  665.     nlinks[0]--;
  666.     for (i=0; i < INODE_ZONES; i++) {
  667.         rd_zone(1+IMAP_ZONES+ZMAP_ZONES+i, zone_buf);
  668.     dirt=0;
  669.     i_pt=(struct xiafs_inode *)zone_buf;
  670.     for (j=0; j < INODES_PER_ZONE; j++) {
  671.         if (nlinks[i*INODES_PER_ZONE+j] &&
  672.             i_pt->i_nlinks != nlinks[i*INODES_PER_ZONE+j]) {
  673.             sprintf(msg,
  674.             "Inode %u (0x%X) has nlinks %u, but recorded as %u.",
  675.             i*INODES_PER_ZONE+j+1, 
  676.             i*INODES_PER_ZONE+j+1, 
  677.             nlinks[i*INODES_PER_ZONE+j], 
  678.             i_pt->i_nlinks);
  679.         if (ask_rep(msg)) {
  680.             i_pt->i_nlinks=nlinks[i*INODES_PER_ZONE+j];
  681.             dirt=1;
  682.         }
  683.         }
  684.         i_pt++;
  685.     }
  686.     if (dirt)
  687.         wt_zone(1+IMAP_ZONES+ZMAP_ZONES+i, zone_buf);
  688.     }
  689. }
  690.       
  691. #define set_bit(bit_nr, buf)     ((buf)[(bit_nr)>>3] |= 1 << ((bit_nr) & 7))
  692. void ck_imap()
  693. {
  694.     int i, j, k, dirt;
  695.     char msg[80];
  696.  
  697.     i=(NR_INODES+1) >> 3;
  698.     memset(imap_buf, 0, i);
  699.     if ( i < IMAP_ZONES*ZONE_SIZE)
  700.         imap_buf[i]=255 << ((NR_INODES+1) & 7);
  701.     if ( i+1 < IMAP_ZONES*ZONE_SIZE)
  702.         memset(imap_buf+i+1, 0xff, IMAP_ZONES*ZONE_SIZE -i-1);
  703.  
  704.     imap_buf[0]=7;
  705.     for (i=2; i < NR_INODES; i++)
  706.         if (nlinks[i])
  707.         set_bit(i+1, imap_buf);
  708.   
  709.     for (i=0; i < IMAP_ZONES; i++) {
  710.         rd_zone(1+i, zone_buf);
  711.     dirt=0;
  712.     for (j=0; j < ZONE_SIZE; j++) {
  713.         if (zone_buf[j]^imap_buf[i*ZONE_SIZE+j]) {
  714.             for (k=0; k < 8; k++) {
  715.             if ((zone_buf[j] & (1<<k)) && 
  716.                     !(imap_buf[i*ZONE_SIZE+j] & (1<<k))) {
  717.                 sprintf(msg, "free inode %u (0x%X) marked as used.", 
  718.                 (i*ZONE_SIZE+j)*8+k, (i*ZONE_SIZE+j)*8+k);
  719.             if (ask_rep(msg)) {
  720.                 zone_buf[j] &= ~(1<<k);
  721.                 dirt=1;
  722.             }
  723.             }
  724.             if (!(zone_buf[j] & (1<<k)) && 
  725.                 (imap_buf[i*ZONE_SIZE+j] & (1<<k))) {
  726.                 sprintf(msg, "used inode %u (0x%X) marked as free.",
  727.                 (i*ZONE_SIZE+j)*8+k, (i*ZONE_SIZE+j)*8+k);
  728.             if (ask_rep(msg)) {
  729.                 zone_buf[j] |= (1<<k);
  730.                 dirt=1;
  731.             }
  732.             }
  733.         }
  734.         }
  735.     }
  736.     if (dirt)
  737.         wt_zone(1+i, zone_buf);
  738.     }
  739. }  
  740.  
  741. /*------------------------------------------------------------------------
  742.  * check zone pointers
  743.  */
  744. #define IS_ZADDR(addr) ((((addr) & 0xffffff)>=first_data_zone && \
  745.              ((addr) & 0xffffff) < zones )|| !((addr) & 0xffffff))
  746.  
  747. void rep_z(struct xiafs_inode * inode_pt, int i)
  748. {
  749.     inode_pt->i_size= i * ZONE_SIZE;
  750.     while (i < 8)
  751.         inode_pt->i_zone[i++]=0;
  752.     inode_pt->i_ind_zone=0;
  753.     inode_pt->i_dind_zone=0;
  754. }
  755.  
  756. void rep_indz(struct xiafs_inode * inode_pt, int i)
  757. {
  758.     inode_pt->i_size= (8+i) * ZONE_SIZE;
  759.     if (i <= 0) {
  760.         inode_pt->i_ind_zone=0;
  761.     inode_pt->i_dind_zone=0;
  762.     return;
  763.     }
  764.     while (i < ADDR_PER_ZONE)
  765.         indz_buf[i++]=0;
  766.     wt_zone(indz_addr, indz_buf);
  767.     inode_pt->i_dind_zone=0;
  768. }
  769.  
  770. void rep_dindz(struct xiafs_inode * inode_pt, int di, int i)
  771. {
  772.     inode_pt->i_size= (8+ (1+di) * ADDR_PER_ZONE + i) * ZONE_SIZE; 
  773.     if (di <= 0) {
  774.         inode_pt->i_dind_zone=0;
  775.     return;
  776.     }
  777.     if (i <= 0) 
  778.         dindz_buf[di]=0;
  779.     else {    
  780.         while (i < ADDR_PER_ZONE) 
  781.         indz_buf[i++]=0;
  782.     wt_zone(indz_addr, indz_buf);
  783.     }
  784.     while (++di < ADDR_PER_ZONE)
  785.         dindz_buf[di]=0;
  786.     wt_zone(dindz_addr, dindz_buf);
  787. }
  788.  
  789. int ck_addr(struct xiafs_inode * inode_pt, int *dirt_flag)
  790. {
  791.     /* return 0 if no error or repaired, -1 if error found but no repair */
  792.  
  793.     int nr_zone, nr_ind, nr_dind, tmp;
  794.     int i, di;
  795.     u_long addr;
  796.     int d_blocks, st_blocks=0;
  797.     char msg_cnfz[]="Conflict zone use.";
  798.     char msg_badz[]="Bad zone pointer.";
  799.     char msg_uxp_badz[]="Bad zone pointer (unexpected error).";
  800.  
  801.     nr_zone=(inode_pt->i_size + ZONE_SIZE -1) / ZONE_SIZE;
  802.     tmp=(nr_zone > 8) ? 8 : nr_zone;
  803.     for (i=0; i < tmp; i++) {
  804.         addr=inode_pt->i_zone[i] & 0xffffff;
  805.     if (addr)
  806.         st_blocks++;
  807.     if ( !IS_ZADDR(addr) || test_set_zbit(addr) ) {
  808.         if (ask_rep( IS_ZADDR(addr) ? msg_cnfz : msg_uxp_badz)) {
  809.             rep_z(inode_pt, i);
  810.         *dirt_flag=1;
  811.         return 0;
  812.         } else 
  813.             return -1;
  814.     } 
  815.     }
  816.     nr_zone -= tmp;
  817.     if (!nr_zone)
  818.         goto block_ck;
  819.     nr_ind=(nr_zone > ADDR_PER_ZONE) ? ADDR_PER_ZONE : nr_zone;
  820.     addr=inode_pt->i_ind_zone & 0xffffff;
  821.     if ( !IS_ZADDR(addr) || test_set_zbit(addr) ) {    /* test indz */
  822.         if (ask_rep( IS_ZADDR(addr) ? msg_cnfz : msg_uxp_badz)) {    
  823.         rep_indz(inode_pt, 0);
  824.         *dirt_flag=1;
  825.         return 0;
  826.     } else
  827.         return -1;
  828.     }
  829.     if (addr) {
  830.         st_blocks++;
  831.         if (indz_addr != addr) {        /* indz is fine and not a big hole */
  832.         indz_addr=addr;            /* load indirect zone ptrs */
  833.         rd_zone(indz_addr, indz_buf);
  834.     }
  835.     for (i=0; i < nr_ind; i++) {        /* test indirect zone ptrs */
  836.         addr=indz_buf[i];
  837.         if (addr)
  838.             st_blocks++;
  839.         if ( !IS_ZADDR(addr) || test_set_zbit(addr) ) {
  840.             if (ask_rep( IS_ZADDR(addr) ? msg_cnfz : msg_badz) ) {
  841.             rep_indz(inode_pt, i);
  842.             *dirt_flag=1;
  843.             return 0;
  844.         } else 
  845.             return -1;
  846.         }
  847.     }
  848.     }
  849.     nr_zone -= nr_ind;
  850.     if (!nr_zone)
  851.         goto block_ck;
  852.     nr_ind=nr_zone & (ADDR_PER_ZONE -1);
  853.     nr_dind=(nr_zone + ADDR_PER_ZONE -1 )/ ADDR_PER_ZONE - 1;
  854.     if (!nr_ind)
  855.         nr_ind=ADDR_PER_ZONE;
  856.     addr=inode_pt->i_dind_zone & 0xffffff;
  857.     if (!IS_ZADDR(addr) || test_set_zbit(addr) ) {
  858.         if (ask_rep( IS_ZADDR(addr) ? msg_cnfz : msg_uxp_badz) ) {
  859.         rep_dindz(inode_pt, 0, 0);
  860.         *dirt_flag=1;
  861.         return 0;
  862.     } else
  863.         return -1;
  864.     }
  865.     if (!addr)
  866.         goto block_ck;                /* a big hole */
  867.     st_blocks++;
  868.     if (dindz_addr != addr) {
  869.         dindz_addr=addr;
  870.     rd_zone(addr, dindz_buf);
  871.     }
  872.     for (di=0; di <= nr_dind; di++ ) {
  873.         addr=dindz_buf[di];
  874.     if ( !IS_ZADDR(addr) || test_set_zbit(addr) ) {
  875.         if (ask_rep(IS_ZADDR(addr) ? msg_cnfz : msg_badz) ) {
  876.             rep_dindz(inode_pt, di, 0);
  877.         *dirt_flag=1;
  878.         return 0;
  879.         } else
  880.             return -1;
  881.     }
  882.     if (!addr)
  883.         continue;
  884.     st_blocks++;
  885.     if (indz_addr != addr) {
  886.         indz_addr=addr;
  887.         rd_zone(addr, indz_buf);
  888.     }
  889.     for (i=0; i < (di==nr_dind ? nr_ind : ADDR_PER_ZONE); i++) {
  890.         addr=indz_buf[i];
  891.         if (addr)
  892.             st_blocks++;
  893.         if ( !IS_ZADDR(addr) || test_set_zbit(addr) ) {
  894.             if (ask_rep( IS_ZADDR(addr) ? msg_cnfz : msg_badz) ) {
  895.             rep_dindz(inode_pt, di, i);
  896.             *dirt_flag=1;
  897.             return 0;
  898.         } else 
  899.             return -1;
  900.         }
  901.     }
  902.     }
  903. block_ck:
  904.     st_blocks <<= 1 + zone_shift;
  905.     d_blocks=((inode_pt->i_zone[0] >> 24) & 0xff) |
  906.       ((inode_pt->i_zone[1] >> 16) & 0xff00) | ((inode_pt->i_zone[2] >> 8) & 0xff0000);
  907.     if ((st_blocks != d_blocks) && ask_rep("bad i_blocks.")) {
  908.         inode_pt->i_zone[0]=(inode_pt->i_zone[0] & 0xffffff) | ((st_blocks << 24) & 0xff000000);
  909.         inode_pt->i_zone[1]=(inode_pt->i_zone[1] & 0xffffff) | ((st_blocks << 16) & 0xff000000);
  910.         inode_pt->i_zone[2]=(inode_pt->i_zone[2] & 0xffffff) | ((st_blocks <<  8) & 0xff000000); 
  911.     *dirt_flag=1;
  912.     }
  913.     return 0;
  914. }
  915.  
  916. /*------------------------------------------------------------------------
  917.  * check file, return 0 mean do not delete, -1 to delete.
  918.  */
  919. int ck_file(struct xiafs_direct *dir_pt)
  920. {
  921.     struct xiafs_inode inode;
  922.     struct xiafs_direct de;
  923.     int tmp, inode_dirt=0;
  924.  
  925.     nlinks[dir_pt->d_ino-1]++;        /* count the # of links */
  926.     if (nlinks[dir_pt->d_ino-1] > 1)    /* hard link, already checked */
  927.         return 0;
  928.     push_de(dir_pt);            
  929.     rd_inode(dir_pt->d_ino, &inode);     /* get inode */
  930.  
  931.     if (S_ISDIR(inode.i_mode) && (inode.i_size & (ZONE_SIZE-1))) {
  932.         tmp=ask_rep("Bad directory size.");
  933.     pop_de();            /* bad size, del */
  934.     return tmp;
  935.     }
  936.     if (inode.i_size > MAX_SIZE ) {
  937.         tmp=ask_rep("size > MAX_SIZE.");
  938.     pop_de(); 
  939.     return tmp;
  940.     }
  941.  
  942.     if ( ck_addr(&inode, &inode_dirt) ) {
  943.         pop_de();
  944.     return 0;                /* error found, no repair */
  945.     }
  946.   
  947.     if (S_ISDIR(inode.i_mode)) {        /* recursive check */
  948.     if ( start_dir(&inode) ) {
  949.         tmp=ask_rep("Bad directory.");
  950.         pop_de();
  951.         return tmp;
  952.     }
  953.  
  954.     while ( (tmp=get_de(&de)) ) {
  955.         if (tmp < 0) {
  956.             if (ask_rep("Bad directory entry."))
  957.             rep_de();
  958.         else {
  959.             end_dir();
  960.             pop_de();
  961.             return 0;
  962.         }
  963.         }
  964.         if (ck_file(&de)) {
  965.             nlinks[de.d_ino-1]--;
  966.             del_de();
  967.         inode_dirt=1;
  968.         }
  969.     }
  970.     end_dir();
  971.     }
  972.  
  973.     if (inode_dirt)
  974.     wt_inode(dir_pt->d_ino, &inode);
  975.     pop_de();
  976.     return 0;
  977. }
  978.  
  979. /*------------------------------------------------------------------------
  980.  * read from the reserved space
  981.  */
  982. void do_read_kern()
  983. {
  984.   struct xiafs_super_block * sp;
  985.   struct boot_text * bp;
  986.   int i, end;
  987.  
  988.   sp=(struct xiafs_super_block *)zone_buf;
  989.   bp=(struct boot_text *)zone_buf;
  990.  
  991.   if ( !sp->s_firstkernzone )
  992.       die("No space reserved for kernel.");
  993.  
  994.   if ( !sp->s_kernzones )
  995.       die("No kernel image is installed.");
  996.  
  997.   if ( sp->s_firstkernzone+sp->s_kernzones > sp->s_firstdatazone )
  998.       die("Bad kernel image size.");
  999.  
  1000.   bp->Istart_sect=1;
  1001.   bp->root_dev=0;
  1002.  
  1003.   if ( write(1, zone_buf, 512) != 512 )
  1004.       die("Write stdout failed");
  1005.  
  1006.   i = sp->s_firstkernzone;
  1007.   end = i + sp->s_kernzones;
  1008.   for (; i < end; i++) {
  1009.       rd_zone(i, zone_buf);
  1010.       if ( write(1, zone_buf, ZONE_SIZE) != ZONE_SIZE )
  1011.       die("write stdout failed");
  1012.   }
  1013. }
  1014.  
  1015. /*------------------------------------------------------------------------
  1016.  * initial buffers
  1017.  */
  1018. void init_buf(int step)
  1019. {
  1020.   if (!step) {
  1021.     zone_buf=(u_char *)malloc(BLOCK_SIZE << 2);
  1022.     if (!zone_buf)
  1023.       die("allocate memory failed");
  1024.   }
  1025.   if (step==1) {
  1026.     zmap_buf=(u_char *)calloc( 1, ZMAP_ZONES * ZONE_SIZE );
  1027.     nlinks=(u_short *)calloc(1, NR_INODES*2 );
  1028.     indz_buf=(u_long *)malloc(ZONE_SIZE);
  1029.     dindz_buf=(u_long *)malloc(ZONE_SIZE);
  1030.     if (!zmap_buf|| !nlinks|| !indz_buf|| !dindz_buf) {
  1031.       sprintf(zone_buf, "allocate memory failed (%d KB needed).",
  1032.           (ZMAP_ZONES*ZONE_SIZE+2*(NR_INODES+ZONE_SIZE)) >> 10);
  1033.       die(zone_buf);
  1034.     }
  1035.   }
  1036. }
  1037.  
  1038. /*----------------------------------------------------------------------
  1039.  * main rutine
  1040.  */
  1041. struct termios term_org, term_raw;
  1042.  
  1043. void clr_up()
  1044. {
  1045.   tcsetattr(0, TCSANOW, &term_org);
  1046.   die("Killed by signal.");
  1047. }
  1048.   
  1049. void main(int argc, char *argv[])
  1050. {
  1051.   int c, raw_term=0;
  1052.   struct xiafs_direct de;
  1053.   extern int optind;
  1054.   
  1055.   pgm_name=argv[0];
  1056.   while ((c=getopt(argc, argv, "akrs")) != EOF) {
  1057.     switch (c) {
  1058.     case 'a': auto_rep=1; break;
  1059.     case 'k': read_kern=1; break;
  1060.     case 'r': rep=1; break;
  1061.     case 's': show_sup=1; break;
  1062.     default :  usage();
  1063.     }
  1064.   }
  1065.   if (auto_rep+rep+show_sup+read_kern > 1) 
  1066.     usage();
  1067.   if (getuid() && (auto_rep+rep))
  1068.     die("repair can only be done by root");
  1069.   if (optind+1 != argc)
  1070.     usage();
  1071.  
  1072.   if ( (dev=open(argv[optind], (auto_rep || rep) ? O_RDWR : O_RDONLY)) < 0)
  1073.     die("opening device fail");
  1074.  
  1075.   init_buf(0);
  1076.   ck_sup_zone();
  1077.  
  1078.   if (show_sup) {
  1079.     show_sup_zone();
  1080.     init_buf(1);
  1081.     de.d_ino=_XIAFS_BAD_INO;
  1082.     de.d_name_len=0;
  1083.     de.d_name[0]=0;
  1084.     if (ck_file(&de))
  1085.         exit(1);
  1086.     show_badblks();
  1087.     exit(0);
  1088.   }
  1089.  
  1090.   if (read_kern) {
  1091.     do_read_kern();
  1092.     exit(0);
  1093.   }
  1094.  
  1095.   init_buf(1);
  1096.   if (rep) {
  1097.     if (!isatty(0) || !isatty(1))
  1098.       die("Need terminal for interactive repair.");
  1099.     tcgetattr(0, &term_org);
  1100.     term_raw=term_org;
  1101.     term_raw.c_lflag &= ~(ICANON|ECHO);
  1102.     signal(SIGINT, clr_up);
  1103.     signal(SIGQUIT, clr_up);
  1104.     signal(SIGTERM, clr_up);
  1105.     tcsetattr(0, TCSANOW, &term_raw);
  1106.     raw_term=1;
  1107.   }
  1108.  
  1109.   de.d_ino=_XIAFS_BAD_INO;
  1110.   de.d_name_len=0;
  1111.   de.d_name[0]=0;
  1112.   ck_file(&de);
  1113.   de.d_ino=_XIAFS_ROOT_INO;
  1114.   de.d_name_len=0;
  1115.   de.d_name[0]=0;
  1116.   ck_file(&de);
  1117.   ck_zmap();
  1118.   ck_nlinks();
  1119.   ck_imap();
  1120.  
  1121.   if (raw_term)
  1122.     tcsetattr(0, TCSANOW, &term_org);
  1123.  
  1124.   if (xiafs_dirt)
  1125.     fprintf(stderr, "\nThe file system has been modified.\n\n"); 
  1126.  
  1127.   exit(0);
  1128. }
  1129.  
  1130.  
  1131.  
  1132.  
  1133.  
  1134.